package com.pig4cloud.pigx.common.security.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Service
@Primary
public class AppTokenServices extends DefaultTokenServices {

	@Autowired
	@Lazy
	private ClientDetailsService clientDetailsService;

	private int accessTokenValiditySeconds = 60 * 60 * 24 * 30;

	@Autowired
	@Lazy
	private TokenStore tokenStore;

	@Transactional
	public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException {

		OAuth2AccessToken existingAccessToken = tokenStore.getAccessToken(authentication);
		if (existingAccessToken != null) {
			if (existingAccessToken.isExpired()) {
				tokenStore.removeAccessToken(existingAccessToken);
			} else {
				tokenStore.storeAccessToken(existingAccessToken, authentication);
				return existingAccessToken;
			}
		}
		DefaultOAuth2AccessToken accessToken = new DefaultOAuth2AccessToken(UUID.randomUUID().toString());
		int validitySeconds = getAccessTokenValiditySeconds(authentication.getOAuth2Request());
		Map addtionalMap = new HashMap<>();
		addtionalMap.put("expires_timestamp", System.currentTimeMillis() + (validitySeconds * 1000L));
			accessToken.setAdditionalInformation(addtionalMap);
			accessToken.setScope(authentication.getOAuth2Request().getScope());
			tokenStore.storeAccessToken(accessToken, authentication);
		return accessToken;
	}


	protected int getAccessTokenValiditySeconds(OAuth2Request clientAuth) {
		if (clientDetailsService != null) {
			ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
			Integer validity = client.getAccessTokenValiditySeconds();
			if (validity != null) {
				return validity;
			}
		}
		return accessTokenValiditySeconds;
	}

	public void afterPropertiesSet() {

	}
}
